﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Engine.Graphics;

namespace Engine.Physics
{
    /// <summary>
    /// Provides a bitfield of layers for collision detection
    /// </summary>
    public enum CollisionLayer
    {
        One = 1,
        Two = 2,
        Three = 4,
        Four = 8
    }

    /// <summary>
    /// Component enabling collsion detection. Uses the attached sprite dimensions by default
    /// </summary>
    public class Collider : Component
    {
        #region fields
        public const CollisionLayer COLLISION_LAYER_ALL = CollisionLayer.One | CollisionLayer.Two | CollisionLayer.Three | CollisionLayer.Four;
        
        public bool IsCentered = false;
        public bool IsStatic = false;
        public CollisionLayer Layer = COLLISION_LAYER_ALL;

        protected Rectangle mAABB;
        protected Vector2 aabbLocation;

        public Rectangle AABB
        {
            get { return mAABB; }
        }

        public CollisionShape Shape
        {
            get;
            protected set;
        }


        public virtual float Width { get { return Shape.Width; } }
        public virtual float Height { get { return Shape.Height; } }

        #endregion

        #region constructors

        public Collider()
        {
        }
        #endregion

        #region Component Inheritance

        public override void OnAdd(GameObject _gameObject)
        {
            base.OnAdd(_gameObject);
            gameObject.collider = this;
        }

        public override void OnRemove()
        {
            gameObject.collider = null;
            PhysicsEngine.Instance.RemoveCollider(this);
            base.OnRemove();
        }

        public override void Awake()
        {
            RecalcAABB();
            PhysicsEngine.Instance.AddCollider(this);
            base.Awake();
        }

        public override void LateUpdate(GameTime _gameTime)
        {
            base.LateUpdate(_gameTime);
            //GraphicsEngine.Instance.DrawGizmo(GraphicsEngine.Instance.MainCamera.WorldToScreen(AABB));
            UpdateShape();
        }

        #endregion

        #region public methods 
        public void UpdateAABB()
        {
            /*if (!gameObject.transform.RotationChanged || (gameObject.rigidbody != null && gameObject.rigidbody.OwnRotation == gameObject.transform.Rotation))
            {
                if (gameObject.transform.PositionChanged || (gameObject.rigidbody != null && gameObject.rigidbody.OwnPosition != Position))
                {
                    aabbLocation += gameObject.transform.PositionDiff;
                    mAABB.Location = new Point((int)Math.Round(aabbLocation.X),
                                               (int)Math.Round(aabbLocation.Y));
                }
            }
            else*/
            {
                RecalcAABB();
            }
        }
        public virtual void RecalcAABB()
        {

        }
        public virtual void UpdateShape()
        {
            UpdateAABB();
        }
        public virtual void RecalcShape()
        {
            RecalcAABB();
        }
        public bool Intersects(Collider _other, out CollisionInfo _collInfo)
        {
            if (_other == null || (Layer & _other.Layer) == 0)
            {
                _collInfo = null;
                return false;
            }

            if (AABB.Intersects(_other.AABB))
            {
                _collInfo = new CollisionInfo(this, _other, Vector2.Zero);
                return GeometryUtils.GJKIntersect(Shape, _other.Shape, ref _collInfo);                 
            }
            _collInfo = null;
            return false;
        }
        #endregion
    }
}
